package com.lid.lib;

import static ohos.agp.components.AttrHelper.getDensity;

import com.lid.lib.utils.TypedAttrUtils;

import ohos.agp.components.AttrHelper;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.util.ArrayList;
import java.util.List;

/**
 * LabelViewHelper;
 *
 * @since 2021-04-13
 */
public class LabelViewHelper {
    private static final int LEFT_TOP = 1;
    private static final int RIGHT_TOP = 2;
    private static final int LEFT_BOTTOM = 3;
    private static final int RIGHT_BOTTOM = 4;

    private static final int DEFAULT_DISTANCE = 50;
    private static final int DEFAULT_HEIGHT = 50;
    private static final int DEFAULT_STROKE_WIDTH = 3;
    private static final int DEFAULT_TEXT_SIZE = 30;
    private static final int DEFAULT_BACKGROUND_COLOR = 0x9F27CDC0;
    private static final int DEFAULT_STROKE_COLOR = 0xFFFFFFFF;
    private static final int DEFAULT_TEXT_COLOR = 0xFFFFFFFF;
    private static final int DEFAULT_ORIENTATION = LEFT_TOP;
    private static final int DEFAULT_TEXT_STYLE = 0;
    private static final int INTIGER = 2;
    private static final float DENSITY = 0.5f;
    private static final float ACTUALDISTANCE = 1.4142135f;
    private static final int ORIENTATION = 4;
    private static final int INT_5 = 5;
    private static final int INT_2 = 2;
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "LabelViewHelper");

    private int mDistance = DEFAULT_DISTANCE;
    private int mHeight = DEFAULT_HEIGHT;
    private int mStrokeWidth = DEFAULT_STROKE_WIDTH;
    private String mText = "HD";
    private Color mBackgroundColor = Color.BLACK;
    private Color mTextColor = Color.BLACK;
    private int mStrokeColor;
    private int mTextSize = DEFAULT_TEXT_SIZE;
    private int mTextStyle = 1;
    private boolean isMvisual = true;
    private int mOrientation = 1;

    private Paint rectPaint;
    private Paint rectStrokePaint;

    private Path rectPath;
    private Path textPath;
    private Paint textPaint;
    private Rect textBound;

    private Context context;
    private int mAlpha;
    private List<Font> fontList;

    /**
     * LabelViewHelper
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public LabelViewHelper(Context context, AttrSet attrs, String defStyleAttr) {
        this.context = context;
        fontList = new ArrayList<Font>();

        fontList.add(Font.DEFAULT_BOLD);
        fontList.add(Font.DEFAULT);
        fontList.add(Font.MONOSPACE);

        mDistance = TypedAttrUtils.getDimensionPixelSize(attrs, "label_distance", DEFAULT_DISTANCE);
        mHeight = TypedAttrUtils.getDimensionPixelSize(attrs, "label_height", DEFAULT_HEIGHT);
        mText = TypedAttrUtils.getString(attrs, "label_text", "HD");
        mBackgroundColor = TypedAttrUtils.getColor(attrs, "label_backgroundColor", Color.BLACK);
        mTextColor = TypedAttrUtils.getColor(attrs, "label_color", Color.WHITE);
        mTextSize = TypedAttrUtils.getDimensionPixelSize(attrs, "label_textSize", DEFAULT_TEXT_SIZE);
        mTextStyle = TypedAttrUtils.getDimensionPixelSize(attrs, "label_textStyle", 1);
        mOrientation = TypedAttrUtils.getDimensionPixelSize(attrs, "label_orientation", 1);

        rectPaint = new Paint();
        rectPaint.setDither(true);
        rectPaint.setAntiAlias(true);
        rectPaint.setStyle(Paint.Style.FILL_STYLE);

        rectStrokePaint = new Paint();
        rectStrokePaint.setDither(true);
        rectStrokePaint.setAntiAlias(true);
        rectStrokePaint.setStyle(Paint.Style.STROKE_STYLE);

        rectPath = new Path();
        rectPath.reset();

        textPath = new Path();
        textPath.reset();

        textPaint = new Paint();
        textPaint.setDither(true);
        textPaint.setAntiAlias(true);
        textPaint.setStyle(Paint.Style.FILL_STYLE);
        textPaint.setStrokeJoin(Paint.Join.ROUND_JOIN);
        textPaint.setStrokeCap(Paint.StrokeCap.SQUARE_CAP);

        textBound = new Rect();
    }

    /**
     * onDraw
     *
     * @param canvas
     * @param measuredWidth
     * @param measuredHeight
     */
    public void onDraw(Canvas canvas, double measuredWidth, double measuredHeight) {
        if (!isMvisual || mText == null) {
            return;
        }
        calcOffset(measuredWidth, measuredHeight);

        rectPaint.setColor(mBackgroundColor);
        if (mAlpha != 0) {
            rectPaint.setAlpha(mAlpha);
        }

        rectStrokePaint.setColor(Color.WHITE);
        rectStrokePaint.setStrokeWidth(mStrokeWidth);

        canvas.drawPath(rectPath, rectPaint);
        canvas.drawPath(rectPath, rectStrokePaint);

        textPaint.setTextSize(mTextSize);
        textPaint.setColor(mTextColor);
        textBound = textPaint.getTextBounds(mText);

        if (mTextStyle == 0) {
            textPaint.setFakeBoldText(true);
            textPaint.setFont(fontList.get(0));
        } else if (mTextStyle == 1) {
            textPaint.setFont(fontList.get(1));
        } else if (mTextStyle == INTIGER) {
            textPaint.setFont(fontList.get(INT_2));
        }

        float actualDistance = (float) (mDistance + mHeight / INTIGER);
        double beginwoffset = (double) ((ACTUALDISTANCE * actualDistance) / (float) INTIGER - textBound.getWidth() / (float) INTIGER);
        if (beginwoffset < 0) {
            beginwoffset = 0;
        }
        canvas.drawTextOnPath(textPaint, mText, textPath, (float) beginwoffset, (float) textBound.getHeight() / (float) INTIGER);
    }

    private void calcOffset(double measuredWidth, double measuredHeight) {
        double startPosX = measuredWidth - mDistance - mHeight;
        double endPosX = measuredWidth;
        double startPosY = measuredHeight - mDistance - mHeight;
        double endPosY = measuredHeight;

        double middle = (double) mHeight / INTIGER;

        switch (mOrientation) {
            case LEFT_TOP: // LEFT_TOP

                rectPath.reset();
                rectPath.moveTo(0, mDistance);
                rectPath.lineTo(mDistance, 0);
                rectPath.lineTo(mDistance + mHeight, 0);
                rectPath.lineTo(0, mDistance + mHeight);
                rectPath.close();

                textPath.reset();
                textPath.moveTo(0, (float) (mDistance + middle));
                textPath.lineTo((float) (mDistance + middle), 0);
                textPath.close();
                break;
            case RIGHT_TOP: // RIGHT_TOP

                rectPath.reset();
                rectPath.moveTo((float) startPosX, 0);
                rectPath.lineTo((float) (startPosX + mHeight), 0);
                rectPath.lineTo((float) endPosX, mDistance);
                rectPath.lineTo((float) endPosX, mDistance + mHeight);
                rectPath.close();

                textPath.reset();
                textPath.moveTo((float) (startPosX + middle), 0);
                textPath.lineTo((float) endPosX, (float) (mDistance + middle));
                textPath.close();
                break;
            case LEFT_BOTTOM: // LEFT_BOTTOM

                rectPath.reset();
                rectPath.moveTo(0, (float) startPosY);
                rectPath.lineTo(mDistance + mHeight, (float) endPosY);
                rectPath.lineTo(mDistance, (float) endPosY);
                rectPath.lineTo(0, (float) (startPosY + mHeight));
                rectPath.close();

                textPath.reset();
                textPath.moveTo(0, (float) (startPosY + middle));
                textPath.lineTo((float) (mDistance + middle), (float) endPosY);
                textPath.close();
                break;
            case RIGHT_BOTTOM: // RIGHT_BOTTOM

                rectPath.reset();
                rectPath.moveTo((float) startPosX, (float) endPosY);
                rectPath.lineTo((float) measuredWidth, (float) startPosY);
                rectPath.lineTo((float) measuredWidth, (float) (startPosY + mHeight));
                rectPath.lineTo((float) startPosX + mHeight, (float) endPosY);
                rectPath.close();

                textPath.reset();
                textPath.moveTo((float) (startPosX + middle), (float) endPosY);
                textPath.lineTo((float) endPosX, (float) (startPosY + middle));
                textPath.close();
                break;
            default:
                break;
        }
    }

    /**
     * dip2Px
     *
     * @param context
     * @param fp
     * @return int
     */
    public static int dip2Px(final Context context, final float fp) {
        return AttrHelper.fp2px(fp, getDensity(context) + DENSITY);
    }

    /**
     * px2Dip
     *
     * @param context
     * @param px
     * @return int
     */
    public static int px2Dip(final Context context, final double px) {
        return (int) Math.round(px * getDensity(context) + DENSITY);
    }

    /**
     * setLabelHeight
     *
     * @param view
     * @param height
     */
    public void setLabelHeight(Component view, int height) {
        if (this.mHeight != dip2Px(context, height)) {
            this.mHeight = dip2Px(context, height);
            view.invalidate();
        }
    }

    public int getLabelHeight() {
        return mHeight;
    }

    /**
     * setLabelDistance
     *
     * @param view
     * @param distance
     */
    public void setLabelDistance(Component view, int distance) {
        if (this.mDistance != dip2Px(context, distance)) {
            this.mDistance = dip2Px(context, distance);
            view.invalidate();
        }
    }

    public int getLabelStrokeWidth() {
        return px2Dip(context, this.mStrokeWidth);
    }

    /**
     * setLabelStrokeWidth
     *
     * @param view
     * @param strokeWidth
     */
    public void setLabelStrokeWidth(Component view, int strokeWidth) {
        if (this.mStrokeWidth != dip2Px(context, strokeWidth)) {
            this.mStrokeWidth = dip2Px(context, strokeWidth);
            view.invalidate();
        }
    }

    public int getLabelDistance() {
        return mDistance;
    }

    public boolean isLabelVisual() {
        return isMvisual;
    }

    /**
     * setLabelVisual
     *
     * @param view
     * @param isVisual
     */
    public void setLabelVisual(Component view, boolean isVisual) {
        if (this.isMvisual != isVisual) {
            this.isMvisual = isVisual;
            view.invalidate();
        }
    }

    public int getLabelOrientation() {
        return mOrientation;
    }

    /**
     * setLabelOrientation
     *
     * @param view
     * @param orientation
     */
    public void setLabelOrientation(Component view, int orientation) {
        if (this.mOrientation != orientation && orientation <= ORIENTATION && orientation >= 1) {
            this.mOrientation = orientation;
            view.invalidate();
        }
    }

    public Color getLabelTextColor() {
        return mTextColor;
    }

    /**
     * setLabelTextColor
     *
     * @param view
     * @param textColor
     */
    public void setLabelTextColor(Component view, Color textColor) {
        if (this.mTextColor != textColor) {
            this.mTextColor = textColor;
            view.invalidate();
        }
    }

    public Color getLabelBackgroundColor() {
        return mBackgroundColor;
    }

    /**
     * setLabelBackgroundColor
     *
     * @param view
     * @param backgroundColor
     */
    public void setLabelBackgroundColor(Component view, Color backgroundColor) {
        if (this.mBackgroundColor != backgroundColor) {
            this.mBackgroundColor = backgroundColor;
            view.invalidate();
        }
    }

    public int getLabelStrokeColor() {
        return mStrokeColor;
    }

    /**
     * setLabelStrokeColor
     *
     * @param view
     * @param strokeColor
     */
    public void setLabelStrokeColor(Component view, int strokeColor) {
        if (this.mStrokeColor != strokeColor) {
            this.mStrokeColor = strokeColor;
            view.invalidate();
        }
    }

    /**
     * setLabelBackgroundAlpha
     *
     * @param view
     * @param alpha
     */
    public void setLabelBackgroundAlpha(Component view, int alpha) {
        if (this.mAlpha != alpha) {
            this.mAlpha = alpha;
            view.invalidate();
        }
    }

    public String getLabelText() {
        return mText;
    }

    /**
     * setLabelText
     *
     * @param view
     * @param text
     */
    public void setLabelText(Component view, String text) {
        if (this.mText == null || !this.mText.equals(text)) {
            this.mText = text;
            view.invalidate();
        }
    }

    public int getLabelTextSize() {
        return mTextSize;
    }

    /**
     * setLabelTextSize
     *
     * @param view
     * @param textSize
     */
    public void setLabelTextSize(Component view, int textSize) {
        if (this.mTextSize != textSize) {
            this.mTextSize = textSize;
            view.invalidate();
        }
    }

    public int getLabelTextStyle() {
        return mTextStyle;
    }

    /**
     * setLabelTextStyle
     *
     * @param view
     * @param textStyle
     */
    public void setLabelTextStyle(Component view, int textStyle) {
        if (this.mTextStyle == textStyle) {
            return;
        }
        this.mTextStyle = textStyle;
        view.invalidate();
    }
}
